package core

import (
	"bytes"
	"fmt"
	"github.com/sirupsen/logrus"
	"io"
	"os"
	"path"
	"sync"
	"time"
	"wecom_rebot/common"
)

// 颜色
const (
	red    = 31
	yellow = 33
	blue   = 36
	gray   = 37
)

const (
	MaxLogSize       = 10 * 1024 * 1024 // 默认 10MB 进行分割
	LogRetentionDays = 30               // 默认保留 30 天
)

var (
	LogDir = "logs" // 日志根目录
)

type LogFormatter struct{}

type scenarioWriter struct {
	scenario    string
	currentFile *os.File
	mu          sync.Mutex
}

func newScenarioWriter(scenario string) io.Writer {
	return &scenarioWriter{scenario: scenario}
}

func (sw *scenarioWriter) Write(p []byte) (n int, err error) {
	sw.mu.Lock()
	defer sw.mu.Unlock()

	dir := fmt.Sprintf("%s/%s", LogDir, sw.scenario)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return 0, err
	}

	if sw.currentFile == nil || sw.shouldRotate() {
		if err := sw.rotateFile(); err != nil {
			return 0, err
		}
	}

	n, err = sw.currentFile.Write(p)
	if err != nil {
		return n, err
	}

	os.Stdout.Write(p) // 同时输出到控制台
	return n, nil
}

func (sw *scenarioWriter) shouldRotate() bool {
	if sw.currentFile == nil {
		return true
	}

	info, err := sw.currentFile.Stat()
	if err != nil {
		return true
	}

	return info.Size() >= MaxLogSize
}

func (sw *scenarioWriter) rotateFile() error {
	if sw.currentFile != nil {
		sw.currentFile.Close()
	}

	filename := sw.generateFilename()
	file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		return err
	}

	sw.currentFile = file
	return nil
}

func (sw *scenarioWriter) generateFilename() string {
	now := time.Now()
	return fmt.Sprintf("%s/%s/%s.log",
		LogDir, sw.scenario,
		now.Format("2006-01-02"))
}

// Format 实现 Formatter(entry *logrus.Entry) ([]byte, error) 接口
func (t LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	// 根据不同的 level 展示不同的颜色
	var levelColor int
	switch entry.Level {
	case logrus.DebugLevel, logrus.TraceLevel:
		levelColor = gray
	case logrus.WarnLevel:
		levelColor = yellow
	case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
		levelColor = red
	default:
		levelColor = blue
	}

	var b *bytes.Buffer
	if entry.Buffer != nil {
		b = entry.Buffer
	} else {
		b = &bytes.Buffer{}
	}

	log := common.Config.Logger

	// 自定义时间格式
	timeStamp := entry.Time.Format("2006-01-02 15:04:05")
	if entry.HasCaller() {
		// 自定义文件路径
		funcVal := entry.Caller.Function
		fileVal := fmt.Sprintf("%s:%d", path.Base(entry.Caller.File), entry.Caller.Line)
		// 自定义格式输出
		fmt.Fprintf(b, "%s[%s] \x1b[%dm[%s]\x1b[0m %s %s %s\n", log.Prefix, timeStamp, levelColor, entry.Level, fileVal, funcVal, entry.Message)
	} else {
		fmt.Fprintf(b, "%s[%s] \x1b[%dm[%s]\x1b[0m %s\n", log.Prefix, timeStamp, levelColor, entry.Level, entry.Message)
	}

	return b.Bytes(), nil
}

// InitLogger 自己封装的 log显示
func InitLogger(scenario string) *logrus.Logger {
	mLog := logrus.New()
	mLog.SetOutput(newScenarioWriter(scenario))
	mLog.SetReportCaller(common.Config.Logger.ShowLine)
	mLog.SetFormatter(&LogFormatter{})
	level, err := logrus.ParseLevel(common.Config.Logger.Level)
	if err != nil {
		level = logrus.InfoLevel
	}
	mLog.SetLevel(level)

	// 调用就可以使用全局log
	InitDefaultLogger(scenario)
	// 启动后台清理任务
	go startCleanupTask()
	return mLog
}

// InitDefaultLogger 修改全局log
func InitDefaultLogger(scenario string) {
	logrus.SetOutput(newScenarioWriter(scenario))
	logrus.SetReportCaller(common.Config.Logger.ShowLine)
	logrus.SetFormatter(&LogFormatter{})
	level, err := logrus.ParseLevel(common.Config.Logger.Level)
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)
}
